package cn.lyf;

import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.annotation.*;

import cn.lyf.conf.MainConfig;
import cn.lyf.listener.*;
import javax.management.InstanceAlreadyExistsException;

/*
spring 容器的刷新工作
1）prepareRefresh
    1) initPropertySources()初始化属性设置
    2） getEnvironment().validateRequiredProperties(); 检验合法性
    3） earlyApplicationEvents()   早期事件
2）obtainFreshBeanFactory 获取beanFactory
   1） refreshBeanFactory()
      beanFactory.setSerializationId(getId()) 设置id

   2） getBeanFactory() 返回创建的beanFactory

   3）prepareBeanFactory(beanFactory)
      1)设置表达式解析器，类解析
      2)添加部分BeanPostProcessor【ApplicationContextAware】
      3)设置忽略的自动装配接口EnvironmentAware
      4)注册可解析的自动装配BeanFactory，ApplicationContext,ResourceLoader,ApplicationEventPublisher
      5)添加后置处理器
      6）给bean中注册一些能用的组件如Environment,systemProperties,systemEnvironment
// 调用流程都在抽象方法中定义好了
    4)PostProcessorBeanFactory()  准备工作完成后的后置处理工作。该方法来自AbstractApplicationContext的一个空方法。可用于扩展
    5）invokeBeanFactoryPostProcessors 执行BeanFactoryPostProcessors
        1）获取所有BeanDefinitionRegistryPostProcessor
           判断是否实现PriorityOrdered接口排序
           判断是否实现Ordered,执行
           执行普通BeanDefinitionRegistryPostProcessor
        2）获取所有BeanFactoryPostProcessors，流程和上面一样

    6）registerBeanPostProcessors()注册beanPostProcessors
         1） 普通beanPostProcessors注册
         2） MergedBeanDefinitionPostProcessor注册
         3）注册 ApplicationListenerDetector

    7）initMessageSource（） 消息解析
       1） 获取bean工厂判断是否有"messageSource" bean存在
            messageSource 用来按照区域信息获取某个key的值

    8）initApplicationEventMulticaster()  初始化事件派发器
       1） 从beanFactory 获取事件派发器,没有spring自己创建一个
    9） onRefresh 留给子容器
    10）registerListeners 注册侦听器
    11）finishBeanFactoryInitialization  初始化bean（单实例，非懒加载，非抽象）
       1）beanFactory.preInstantiateSingletons
           1）判断是否是工厂bean，用getObject创建
           2）普通bean用getBean
                1) doGetBean 先获取缓存中的bean 【sharedInstance】
                2) 获取不到开始创建
                     1）标记bean已经被创建
                     2)获取定义信息
                     2）获取依赖信息 depends-on,先创建依赖
                     7） 启动单实例创建流程
                         1) createBean
                              1) resolveBeforeInstantiation  执行 InstantiationAwareBeanPostProcessors  给一个返回代理对象的机会
                              2）如果前面没返回 beanInstance = doCreateBeanInstance
                                  1) createBeanInstance
                                  2) applyMergedBeanDefinitionPostProcessor调用MergedBeanDefinition
                                  3) populateBean  属性赋值
                                        1)InstantiationAwareBeanPostProcessor执行
                                            1,postProcessAfterInstantiation
                                            2,postProcessPropertyValues
                                        2）applyPropertyValues 属性赋值
                                  4)bean【初始化】
                                     1）执行xxxAware接口
                                     2）BeanPostProcessor.postProcessBeforeInitialization()
                                     3) invoke 执行初始化方法
                                     4）注册销毁方法
                    8） 检查是否是SmartInitializingSingleton,执行afterSingletonsInstantiated
    12）finishRefresh() 最后一步：发布相应的事件。
		1）initLifecycleProcessor();  注册生命周期的后置处理器【lifecycleProcessor】
		2）getLifecycleProcessor().onRefresh(); 获取生命周期的后置处理器调用onRefresh
		3）publishEvent(new ContextRefreshedEvent(this)); 发布容器刷新完成事件
		4）LiveBeansView.registerApplicationContext(this);




 */
public class App {
    static AnnotationConfigApplicationContext applicationContext;

    public static void main(String[] args) {
        applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        // 设置环境 applicationContext.getEnvironment().setActiveProfiles(profiles);
        // 注册配置类 applicationContext.register(annotatedClasses);
        // 启动刷新 applicationContext.refresh();

        for (String beanName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanName);
        }
        System.out.println(applicationContext.getEnvironment().getProperty("os.name"));
        applicationContext.getBean(App.class) .hello();
        // 主动触发事件
        applicationContext.publishEvent(new MyEvent(applicationContext));
        applicationContext.close();

    }

    public void hello() {
        System.out.println("Hello!");
    }
}
